
%token <string> ID
%token <int> INT
%token <string> STRING
%token <float> FLOAT

%token OPEN CLOSE LBRACK RBRACK

%token KW_FALSE KW_TRUE
%token KW_LET KW_REC KW_IN
%token KW_IF KW_THEN KW_ELSE
%token KW_FUN  
%token KW_OR KW_AND
%token KW_FST KW_SND
%token KW_HEAD KW_TAIL KW_NIL


%token OR ARROW CONS COMMA SEMICOLON
%token LT LE EQ NE GE GT
%token AND LAND LOR KW_NOT
%token EOL
%token PLUS MINUS UMINUS TIMES DIVIDE PLUSF MINUSF TIMESF DIVIDEF MOD MODF


%right ARROW
%nonassoc KW_IN KW_THEN KW_AS
%left KW_ELSE
%left KW_OR LOR
%left AND LAND
%nonassoc LT LE EQ NE GE GT
%left COMMA SEMICOLON
%nonassoc MOD MODF
%left PLUS MINUS PLUSF MINUSF
%left TIMES DIVIDE TIMESF DIVIDEF
%right KW_NOT
%right CONS
%right KW_FST KW_SND
%nonassoc UMINUS NIL
%left OPEN LBRACK CLOSE RBRACK



%start main
%type <Ast.t> main

%%

main:
  expr EOL { $1 }
;

const:
  KW_FALSE { Const.Bool false }
| KW_TRUE { Const.Bool true }
| INT { Const.Int $1 }
| FLOAT { Const.Float $1 }
| STRING { Const.String $1 }
| OPEN const COMMA const CLOSE {Const.Pair ($2,$4) }
;

expr:
  const { Ast.Const $1 }
| ID { Ast.Id $1 }
| LBRACK val_list RBRACK { $2 }
| KW_NIL { Ast.Op ("nil", [])}
| KW_FST expr { Ast.Op("fst", [$2]) }
| KW_SND expr { Ast.Op("snd", [$2]) }
| KW_NOT expr { Ast.Op("notBool", [$2]) }
| KW_HEAD expr { Ast.Op ("head", [$2])}
| KW_TAIL expr { Ast.Op ("tail", [$2])}
| UMINUS expr { Ast.Op("negIng", [$2]) }
| expr CONS expr { Ast.Op ("cons", [$1;$3])}
| expr PLUS expr { Ast.Op("addInt", [$1;$3]) }
| expr PLUSF expr { Ast.Op("addFloat", [$1;$3]) }
| expr MINUS expr { Ast.Op("subInt", [$1;$3]) }
| expr MINUSF expr { Ast.Op("subFloat", [$1;$3]) }
| expr TIMES expr { Ast.Op("mulInt", [$1;$3]) }
| expr TIMESF expr { Ast.Op("mulFloat", [$1;$3]) }
| expr DIVIDE expr { Ast.Op("divInt",[$1;$3]) }
| expr DIVIDEF expr { Ast.Op("divFloat",[$1;$3]) }
| expr MOD expr { Ast.Op("modInt",[$1;$3]) }
| expr MODF expr { Ast.Op("modFloat",[$1;$3]) }
| expr AND expr { Ast.Op("And", [$1;$3]) }
| expr KW_OR expr { Ast.Op("Or", [$1;$3]) }
| expr LAND expr { Ast.Op("andBool", [$1;$3]) }
| expr LOR expr { Ast.Op("orBool", [$1;$3]) }
| expr EQ expr { Ast.Op("eq", [$1;$3]) }
| expr NE expr { Ast.Op("ne", [$1;$3]) }
| expr LE expr { Ast.Op("le", [$1;$3]) }
| expr LT expr { Ast.Op("lt", [$1;$3]) }
| expr GE expr { Ast.Op("ge", [$1;$3]) }
| expr GT expr { Ast.Op("gt", [$1;$3]) }
| OPEN expr expr_ne_list CLOSE { Ast.Apply ($2,$3) }
| OPEN expr CLOSE { $2 }
| KW_FUN arg_ne_list ARROW expr { Ast.Fun($2,$4) }
| KW_LET dec_list KW_IN expr { Ast.Let ($2,$4) }
| KW_LET KW_REC dec_list KW_IN expr { Ast.LetRec($3,$5) }
| KW_IF expr KW_THEN expr KW_ELSE expr { Ast.If($2,$4,$6) }
;

val_list:
  { Ast.Op ("nil",[]) }
| val_ne_list { Ast.Op("cons2",[Ast.Op ("nil",[]);$1]) }
;

val_ne_list:
  const                       { Ast.Const $1 }
| const SEMICOLON val_ne_list { Ast.Op ("cons2", [Ast.Const $1;$3]) }
;

dec_list:
  ID EQ expr             { [$1,$3] }
| ID arg_ne_list EQ expr {[($1,Ast.Fun($2,$4))] }
|dec_list dec_list       { $1 @ $2 }
;

expr_ne_list:
  expr { [$1] }
| expr expr_ne_list { $1::$2 }
;


arg_ne_list:
  ID { [$1] }
| ID arg_ne_list { $1::$2 }
;


/*
fun_list:
 ID arg_list EQ expr {[($1,Ast.Fun($2,$4))] }
|fun_list fun_list   { $1 @ $2 }
;

arg_list:
  { [] }
| arg_ne_list { $1 }
;

list_content:
  { [] }
| list_ne_content { $1 }
;

list_ne_content:
  expr { [$1] }
| expr list_ne_content { $1::$2 }
;
*/
